home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include "global.h"
- #include "mbuf.h"
- #include "timer.h"
- #include "icmp.h"
- #include "netuser.h"
- #include "tcp.h"
- #include "telnet.h"
- #include "session.h"
-
- #define TUMAXSCAN 3 /* max number of telunix clients active */
- #define TURQSIZ 512 /* max data we will request from pty at once */
-
- struct tcb *tnix_tcb = NULLTCB;
- struct tcb *tnixtcb[TUMAXSCAN]; /* savebuf for tcb ptrs for scan routines */
- extern int errno;
-
- /* Start telnet-unix server */
- tnix1(argc,argv)
- char *argv[];
- {
- struct socket lsocket;
- extern int32 ip_addr;
- void tnix_state();
-
- /* Incoming Telnet */
- lsocket.address = ip_addr;
-
- if(argc < 2)
- lsocket.port = TELNET_PORT;
- else
- lsocket.port = atoi(argv[1]);
-
- tnix_tcb = open_tcp(&lsocket,NULLSOCK,TCP_SERVER,0,
- NULLVFP,NULLVFP,tnix_state,0,(char *)NULL);
-
- if(tnix_tcb == NULLTCB)
- fprintf(stderr,"start telunix fails rsn %d.\n",net_error);
- else
- log(tnix_tcb,"STARTED Telunix - (%d %x)",
- lsocket.port,tnix_tcb);
- }
-
- /* Shut down Telnet server */
- tnix0()
- {
- if(tnix_tcb != NULLTCB) {
- log(tnix_tcb,"STOPPED Telunix - (%x)",tnix_tcb);
- close_tcp(tnix_tcb);
- } else
- fprintf(stderr,"stop telunix fails -- no server active.\n");
- }
-
- /* Handle incoming Telnet-Unix connect requests */
- static void
- tnix_state(tcb,old,new)
- struct tcb *tcb;
- char old,new;
- {
- register int i;
- register struct telnet *tn;
- int tnix_addscan();
- extern void tnix_rmvscan();
- extern int send_tcp();
- extern struct mbuf *free_p();
- extern int del_tcp();
- extern int close_tcp();
- extern void free();
-
- tn = (struct telnet *)tcb->user;
-
- switch(new){
- case ESTABLISHED:
- /* Create and initialize a Telnet protocol descriptor */
- if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
- log(tcb,"reject Telunix - no space");
- sndmsg(tcb,"Rejected; no space on remote\n");
- close_tcp(tcb);
- return;
- }
- tn->session = NULLSESSION;
- tn->state = TS_DATA;
- tcb->user = (char *)tn; /* Upward pointer */
- tn->tcb = tcb; /* Downward pointer */
- tn->inbuf = NULLBUF;
- tn->outbuf = NULLBUF;
- if(tnix_addscan(tcb) < 0 ||
- (tn->fd = OpenPty()) < 3) { /* barf if <= stderr */
- tnix_rmvscan(tcb);
- log(tcb,"reject Telunix - no Unix ports");
- sndmsg(tcb,
- "Rejected; no ports available on remote\n");
- close_tcp(tcb);
- return;
- }
- log(tcb,"open Telunix - (%d %x %d %d)",tn->fd,tcb,old,new);
- break;
-
- case FINWAIT1:
- case FINWAIT2:
- case CLOSING:
- case LAST_ACK:
- case TIME_WAIT:
- if(tn != NULLTN &&
- tn->fd > 2) {
- log(tcb,"close Telunix - (%d %x %d %d)",
- tn->fd,tcb,old,new);
- close(tn->fd);
- tn->fd = 0;
- }
- tnix_rmvscan(tcb);
- break;
-
- case CLOSE_WAIT:
- /* flush that last buffer */
- if(tn != NULLTN &&
- tn->outbuf != NULLBUF &&
- tn->outbuf->cnt != 0) {
- send_tcp(tcb,tn->outbuf);
- tn->outbuf = NULLBUF;
- }
- close_tcp(tcb);
- break;
-
- case CLOSED:
- if(tn != NULLTN) {
- if(tn->fd > 2) {
- log(tcb,"close Telunix - (%d %x %d %d)",
- tn->fd,tcb,old,new);
- close(tn->fd);
- tn->fd = 0;
- }
- if(tn->inbuf != NULLBUF)
- free_p(tn->inbuf);
- if(tn->outbuf != NULLBUF)
- free_p(tn->outbuf);
- free((char *)tn);
- }
- tnix_rmvscan(tcb);
- del_tcp(tcb);
- if(tcb == tnix_tcb)
- tnix_tcb = NULLTCB;
- break;
- }
- }
-
- /* Telunix io interface. Called periodically to process any waiting io. */
- void
- tnix_try(tcb)
- register struct tcb *tcb;
- {
- extern void tnix_rmvscan();
- extern int recv_tcp();
- extern int send_tcp();
- extern void tnix_input();
-
- register struct telnet *tn;
- register int i;
-
- if((tn = (struct telnet *)tcb->user) == NULLTN || tn->fd < 3) {
- /* Unknown connection - remove it from queue */
- log(tcb,"error Telnet - tnix_try (%d)", tn);
- tnix_rmvscan(tcb);
- return;
- }
- /*
- * First, check if there is any pending io for the pty:
- */
- if(tn->inbuf != NULLBUF) {
- tnix_input(tn);
- }
- if(tn->inbuf == NULLBUF) {
- if(tcb->rcvcnt > 0 &&
- recv_tcp(tcb,&(tn->inbuf),0) > 0)
- tnix_input(tn);
- }
- /*
- * Next, check if there is any io for tcp:
- */
- do {
- if(tn->outbuf == NULLBUF &&
- (tn->outbuf = alloc_mbuf(TURQSIZ)) == NULLBUF)
- return; /* can't do much without a buffer */
-
- if(tn->outbuf->cnt < TURQSIZ) {
- if((i = read(tn->fd, tn->outbuf->data + tn->outbuf->cnt,
- TURQSIZ - tn->outbuf->cnt)) == -1) {
- log(tcb,"error Telunix - read (%d %d %d)",
- errno, tn->fd,
- TURQSIZ - tn->outbuf->cnt);
- close_tcp(tcb);
- return;
- }
- if((tn->outbuf->cnt += i) < TURQSIZ)
- i = 0; /* didn't fill buffer so don't retry */
- } else {
- i = -1; /* any nonzero value will do */
- }
- if(tn->outbuf->cnt == 0 || /* nothing to send */
- tcb->sndcnt > tcb->window) /* too congested to send */
- return;
- if(send_tcp(tcb,tn->outbuf) < 0) {
- log(tcb,"error Telunix - send_tcp (%d %d %d)",
- net_error, tn->fd, tn->outbuf->cnt);
- close_tcp(tcb);
- tn->outbuf = NULLBUF;
- return;
- }
- tn->outbuf = NULLBUF;
- } while(i);
- }
-
- /* Process incoming TELNET characters */
- void
- tnix_input(tn)
- register struct telnet *tn;
- {
- void doopt(),dontopt(),willopt(),wontopt(),answer();
- char *memchr();
- register int i;
- register struct mbuf *bp;
- char c;
-
- bp = tn->inbuf;
-
- /* Optimization for very common special case -- no special chars */
- if(tn->state == TS_DATA){
- while(bp != NULLBUF &&
- memchr(bp->data,IAC,bp->cnt) == NULLCHAR) {
- if((i = write(tn->fd, bp->data, bp->cnt)) == bp->cnt) {
- tn->inbuf = bp = free_mbuf(bp);
- } else if(i == -1) {
- log(tn->tcb,"error Telunix - write (%d %d %d)",
- errno, tn->fd, bp->cnt);
- close_tcp(tn->tcb);
- return;
- } else {
- bp->cnt -= i;
- bp->data += i;
- return;
- }
- }
- if(bp == NULLBUF)
- return;
- }
- while(pullup(&(tn->inbuf),&c,1) == 1){
- bp = tn->inbuf;
- switch(tn->state){
- case TS_DATA:
- if(uchar(c) == IAC){
- tn->state = TS_IAC;
- } else {
- if(!tn->remote[TN_TRANSMIT_BINARY])
- c &= 0x7f;
- if(write(tn->fd, &c, 1) != 1) {
- /* we drop a character here */
- return;
- }
- }
- break;
- case TS_IAC:
- switch(uchar(c)){
- case WILL:
- tn->state = TS_WILL;
- break;
- case WONT:
- tn->state = TS_WONT;
- break;
- case DO:
- tn->state = TS_DO;
- break;
- case DONT:
- tn->state = TS_DONT;
- break;
- case IAC:
- if(write(tn->fd, &c, 1) != 1) {
- /* we drop a character here */
- return;
- }
- tn->state = TS_DATA;
- break;
- default:
- tn->state = TS_DATA;
- break;
- }
- break;
- case TS_WILL:
- willopt(tn,c);
- tn->state = TS_DATA;
- break;
- case TS_WONT:
- wontopt(tn,c);
- tn->state = TS_DATA;
- break;
- case TS_DO:
- doopt(tn,c);
- tn->state = TS_DATA;
- break;
- case TS_DONT:
- dontopt(tn,c);
- tn->state = TS_DATA;
- break;
- }
- }
- }
-
- /* called periodically from main loop */
- void
- tnix_scan()
- {
- void tnix_try();
- register int i;
-
- for(i = 0; i < TUMAXSCAN; i += 1)
- if(tnixtcb[i] != NULLTCB)
- tnix_try(tnixtcb[i]);
- }
-
- int
- tnix_addscan(tcb)
- struct tcb *tcb;
- {
- register int i;
- for(i = 0; i < TUMAXSCAN; i += 1)
- if(tnixtcb[i] == NULLTCB) {
- tnixtcb[i] = tcb;
- return i;
- }
- return -1;
- }
-
- void
- tnix_rmvscan(tcb)
- struct tcb *tcb;
- {
- register int i;
-
- for(i = 0; i < TUMAXSCAN; i += 1)
- if(tnixtcb[i] == tcb)
- tnixtcb[i] = NULLTCB;
- }
-